﻿/*  ################################################### */
/*  ##    AIMLbot Chat tool for Glider by Zeo80      ## */
/*  ##                                               ## */
/*  ##            Based on the AIMLbot               ## */
/*  ##        http://aimlbot.sourceforge.net/        ## */
/*  ################################################### */

using System;
using System.Collections;
using System.ComponentModel;
using System.Threading;
using System.IO;
using AIMLbot;
using Glider.Common.Objects;
using System.Windows.Forms;
using Vigo.AdvancedClipboard;
using System.Xml;
using System.Text.RegularExpressions;
using System.Net;

namespace AIML
{
    public class ChatBot
    {

        #region Developers Settings

        public static string Version = "v1.1.1";                                // Version number of this release
        static string VersionStr = "111";                                       // Version Srting for compairing with current

        static public string WhisperCommand = "/w ";                            // What code to send post name + message
        static string SayCommand = "/s ";                                       // What code to send post say message

        static string say_indentifyer = "] says: ";                             // Unique part to find a say in the ChatLog
        static string whisper_indentifyer = "] whispers: ";                     // Unique part to find a whisper in the ChatLog
        static int NameStartPosition = 1;                                       // Position of name start in ChatLog (Sender)

        static string GM_Indentifyer = "UI-ChatIcon-Blizz.blp";                 // Unique part to find a GM whisper in the ChatLog
        static int GMNameStartPosition = 56;                                    // Position of name start in ChatLog (if GM is Sender)

        static string Guild_indentifyer = "|Hchannel:Guild|h[Guild]|h |Hplayer:"; // Unique part to find a Guild text in the ChatLog - Changed for WoW v.3.0.x

        static string BG_indentifyer = "[Battleground]";                        // Unique part to find BG chats in the ChatLog
        static string BGCommand = "/bg ";                                       // What code to send post BG message

        static string invite_indentifyer = "] has invited you to";              // Unique part to find a invite in the ChatLog
        static int InviteNameStartPosition = 1;                                 // Position of name start in ChatLog (On invite)

        static string duel_indentifyer = "AutoDecline: Duel challenge from ";   // Unique part to find a duel request in the ChatLog

        static int MaxLevenshteinDistance = 30;                                 // Max. (%) of comparable messages recently send

        static string DNDflag = "<DND>";                                        // post flag by DND players
        static string AFKflag = "<AFK>";                                        // post flag by AFK players

        public static string EmplyReplacement = "#";                            // When saving a string that is emply in advance settings this character will be stored instead.


        /*  ######################################## */
        /*  ##    Keyboard and Random setting     ## */
        /*  ######################################## */

        static string[] Emotes = {                                              // Ways to emote to a other player
                "/hi", "/hello", "/chicken", "/train", "/lol", "/thanks", "/flirt", "/sexy", "/silly", "/bye", "/wave", "/dance"
            };

        static char[] Alphabet = {                                              // Origional characters to replace
                'a', 'b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'
            };
        static char[] TypoList1 = {                                             // Coresponding characters to the right of the keyboard
                's', 'n','v','f','r','g','h','j','o','k','l',';',',','m','p','[','w','t','d','y','i','b','e','c','u','x'
            };
        static char[] TypoList2 = {                                             // Coresponding characters to the left of the keyboard
                'q', 'v','x','s','w','d','f','g','u','h','j','k','n','b','i','o','1','e','s','r','y','c','q','z','t','a'
            };
        #endregion

        #region Variables setup
        /*  ################################################### */
        /*  ##                 Actual code                   ## */
        /*  ################################################### */

        public static string MyToonName = "";                               
        public static bool StopGliding;                                         // Set it to false and it will not stop gliding, the normal class keystrokes can conflict
        public static bool GM_Reply_on;                                         // Set it to false and it will not reply to a GM
        public static bool AvoidSelfLoop;                                       // Set it to false and it will not avoid the loop when whispering your self
        public static bool RandomMove;                                          // Set it to false and you will never jump or move during typing
        public static bool SendDefault;                                         // Set it to false and you will never Reply the default reply
        public static int JumpLikelihood;                                       // How likely to jump when enabled during typing in percentages else it will move a bit randomly
        public static string GM_Reply;                                          // What will you send to a GM before loggin off
        public static int CharDelay;                                            // Time (milliseconds) per character to simulate typing a random of 20% will be added
        public static ArrayList WhiteList = new ArrayList();                    // List of people we say stuff back to
        public static ArrayList BlackList = new ArrayList();                    // List of people we ignore
        public static ArrayList GraykList = new ArrayList();                    // List of people we recieved Say/Whispers from to keep a count
        public static ArrayList MessageSend = new ArrayList();                  // List of messages send recently to avoid repeating

        public static bool UseBlacklist;                                        // Set it to false and nobody will be added to the blacklist
        public static int MaxBlacklistCount;                                    // At this number of Blacklist incidents I Hearth and Exit
        public static int BlacklistCount = 0;                                   // How much time did we find someone on our blacklist

        public static bool UseMisspell;                                         // Set it to false and you will never misspell
        public static int misspellLikelihood;                                   // How likely to misspel a letter
        public static string MisspellCorrection = "";                           // This wil contain the misspelled word
        public static bool UseMisspellCorrection;                               // Set it to false and you will never send corrections

        public static bool AppriciatHeal;                                       // Set it to false and you won't show appreciation for friendly a heal
        public static bool AppriciatBuff;                                       // Set it to false and you won't show appreciation for friendly a buff
        public static GSpellTimer AppriciatTimer;                               // Minimum time between appreciations

        public static bool UseFace;                                             // Set it to false and it will not turn to face the one you’re speaking to
        public static bool UseSay;                                              // Set it to false and it will not reply to a say
        public static bool UseWhisper;                                          // Set it to false and it will not reply to a whisper
        public static string triger1;                                           // A text to respond to in a say
        public static string triger2;                                           // A text to respond to in a say
        public static string triger3;                                           // A text to respond to in a say
        public static string triger4;                                           // A text to respond to in a say

        public static int MaxGrayListCount;                                     // At this number of Graylist incidents the person is put on the blacklist

        public static bool UseInvite;                                           // Set it to false and you will not respond to a group invite

        public static bool UseInitiateChat;                                     // Set it to false and you will not address a person very close
        public static int VeryCloseDistance;                                    // If a player is this close initiate a chat

        public static int CloseDistance;                                        // If only one player is this close we consider he is speaking to us (/say)

        public static bool UseRemoveDot;                                        // Set it to false and you will send a . at the end of the messages

        public static bool UseEmote;                                            // If set to false you will say to people from the other faction

        public static bool ManualChat = true;                                   // If set to true it will ask you what to send back.

        public static GSpellTimer CleanMessageSendTimer;                        //timer before cleaning MessageSend

        public static ArrayList Appriciation = new ArrayList();
        public static ArrayList Correction = new ArrayList();
        public static ArrayList Invite = new ArrayList();
        public static ArrayList Opening = new ArrayList();
        public static ArrayList BG = new ArrayList();

        public static ArrayList BGpositive = new ArrayList();
        public static ArrayList BGnegative = new ArrayList();

        public static ArrayList Duel = new ArrayList();

        public static ArrayList DefaultMesg = new ArrayList();
        

        public static string LastFrom = "";                                     // Contains the lastest from, for multi threath, for multi threath
        public static string SendMessage;                                       // Contains the message to send

        public static GSpellTimer BGTimer;
        public static bool UseBGChat;

        public static string ManualChatWith = "";                               // This person you will manually chat with
        public static string ManualMessage = "";                                // Message from ManualChatWith

        public static bool MSNsay = true;                                       // If false no say info is send to the MSN monitor
        public static bool MSNsend = true;                                      // If false no sended info is send to the MSN monitor
        public static bool MSNguild = false;                                    // If false no Guild info is send to the MSN monitor
        public static bool MSNbg = false;                                       // If false no battleground info is send to the MSN monitor

        public static bool TryIcon = true;                                       // If true, monitorbox will close to sys.tray icon

        public static string MSNmessage = "";                                   // When this contains text it is passed to the MSN monitor

        static Form MonitorBox = new MonitorBox1();
        static MonitorBox1 MonitorLog;

        static string LastInviteFrom;                                           // This will contain the person who send you the last invite
        static int LastInviteCount = 0;                                         // This will count the number of invites in a raw from one person
        static int InviteMax;                                                   // Max number of invites in a row from one person
        static string InviteMaxMessage;                                         // What to send after max invites

        public static bool AIMLfeedback = true;                                 // If false no AIML information will be send to the developers server

        static int MaxWords = 10;

        public static int DeadCount = 0;
        public static int BGCount = 0;
        public static int KillCount = 0;

        static int LookingTime;

        static int LatestLVL = 0;
        static bool SetLevel = false;

        static string OldUser = "Default";

        public static bool AIMLautoanswer = true;

        public static bool BGEventsUse;
        public static int BGEventsLikelihood;

        static bool UseDuel;

        static int RemainingFiles = 0;

        static string Watching = "";

        #endregion

        //--------------------------------------Default GConfig---------------------------------------------

        static void SetDefault(string name, string value, bool over)
        {
            if (GContext.Main.GetConfigString(name) == null)  GContext.Main.SetConfigValue(name, value, over);
        }

        public static void CreateDefaultConfig()                                // Default settings for GConfig
        {

            SetDefault("AIMLBot.AutoMSN", "False", false);
            SetDefault("AIMLBot.StopGlide", "True", false);
            SetDefault("AIMLBot.StopLoop", "True", false);
            SetDefault("AIMLBot.CharDelay", "333", false);
            SetDefault("AIMLBot.RandomMove", "True", false);
            SetDefault("AIMLBot.JumpLike", "40", false);
            SetDefault("AIMLBot.DWhisper", "True", false);

            SetDefault("AIMLBot.DReply1", "No time for chat", false);         
            SetDefault("AIMLBot.DReply2", "nvm", false);
            SetDefault("AIMLBot.DReply3", "I am very busy", false);
            SetDefault("AIMLBot.DReply4", "Cheers", false);

            SetDefault("AIMLBot.GMReply", "True", false);
            SetDefault("AIMLBot.GMWhisper", "I am about to logoff, cjao", false);
            SetDefault("AIMLBot.UseBlacklist", "True", false);
            SetDefault("AIMLBot.MaxBlacklistCount", "5", false);
            SetDefault("AIMLBot.TYHeal", "True", false);
            SetDefault("AIMLBot.TYBuff", "True", false);
            SetDefault("AIMLBot.UseFace", "True", false);
            SetDefault("AIMLBot.UseSay", "True", false);
            SetDefault("AIMLBot.UseWhisper", "True", false);
            SetDefault("AIMLBot.Keyword1", "reporting you", false);
            SetDefault("AIMLBot.Keyword2", "Glider?", false);
            SetDefault("AIMLBot.Keyword3", "idiot!", false);
            SetDefault("AIMLBot.Keyword4", "hate you", false);
            SetDefault("AIMLBot.TYTime", "3", false);
            SetDefault("AIMLBot.MaxGraylistCount", "6", false);
            SetDefault("AIMLBot.MSGTime", "2", false);
            SetDefault("AIMLBot.UseMisspell", "True", false);
            SetDefault("AIMLBot.MisspellLikelihood", "20", false);
            SetDefault("AIMLBot.UseMisspellCorrection", "True", false);
            SetDefault("AIMLBot.UseInvite", "True", false);
            SetDefault("AIMLBot.UseInitiate", "False", false);
            SetDefault("AIMLBot.InitiateDistance", "20", false);
            SetDefault("AIMLBot.LookForCloseDistance", "35", false);
            SetDefault("AIMLBot.UseRemoveDot", "True", false);
            SetDefault("AIMLBot.UseEmote", "True", false);
            SetDefault("AIMLBot.UseBGchat", "True", false);
            SetDefault("AIMLBot.BGTime", "600", false);

            SetDefault("AIMLBot.Appriciation1", "ty", false);
            SetDefault("AIMLBot.Appriciation2", "thx", false);
            SetDefault("AIMLBot.Appriciation3", "tyvm", false);
            SetDefault("AIMLBot.Appriciation4", "TY", false);
            SetDefault("AIMLBot.Appriciation5", "Thanks", false);
            SetDefault("AIMLBot.Appriciation6", "ty", false);
            SetDefault("AIMLBot.Appriciation7", "Tyvm", false);
            SetDefault("AIMLBot.Appriciation8", "Thx", false);
            SetDefault("AIMLBot.Appriciation9", "thanks", false);
            SetDefault("AIMLBot.Appriciation10", "TYVM", false);
            SetDefault("AIMLBot.Appriciation11", "xD", false);
            SetDefault("AIMLBot.Appriciation12", "", false);
            SetDefault("AIMLBot.Appriciation13", "", false);
            SetDefault("AIMLBot.Appriciation14", "", false);
            SetDefault("AIMLBot.Appriciation15", "", false);
            SetDefault("AIMLBot.Appriciation16", "", false);
            SetDefault("AIMLBot.Appriciation17", "", false);
            SetDefault("AIMLBot.Appriciation18", "", false);
            SetDefault("AIMLBot.Appriciation19", "", false);
            SetDefault("AIMLBot.Appriciation20", "", false);

            SetDefault("AIMLBot.Correction1", "* ##", false);
            SetDefault("AIMLBot.Correction2", "sry ## ofc", false);
            SetDefault("AIMLBot.Correction3", "oeps ##", false);
            SetDefault("AIMLBot.Correction4", "##", false);
            SetDefault("AIMLBot.Correction5", " ##", false);
            SetDefault("AIMLBot.Correction6", "typo ## sry", false);
            SetDefault("AIMLBot.Correction7", "eh correct ##", false);
            SetDefault("AIMLBot.Correction8", "dhu ##, lol", false);
            SetDefault("AIMLBot.Correction9", "damn ##", false);
            SetDefault("AIMLBot.Correction10", "** ## ;)", false);
            SetDefault("AIMLBot.Correction11", "Sorry ## my fingers hurt", false);
            SetDefault("AIMLBot.Correction12", "i mean ## sorry", false);
            SetDefault("AIMLBot.Correction13", "i mean ##", false);
            SetDefault("AIMLBot.Correction14", "", false);
            SetDefault("AIMLBot.Correction15", "", false);
            SetDefault("AIMLBot.Correction16", "", false);
            SetDefault("AIMLBot.Correction17", "", false);
            SetDefault("AIMLBot.Correction18", "", false);
            SetDefault("AIMLBot.Correction19", "", false);
            SetDefault("AIMLBot.Correction20", "", false);

            SetDefault("AIMLBot.Invite1", "I prefer to play alone", false);
            SetDefault("AIMLBot.Invite2", "I am just grinding", false);
            SetDefault("AIMLBot.Invite3", "I am not a real team player", false);
            SetDefault("AIMLBot.Invite4", "no, but thanks for the invite", false);
            SetDefault("AIMLBot.Invite5", "I play solo", false);
            SetDefault("AIMLBot.Invite6", "thanks, but no thanks ", false);
            SetDefault("AIMLBot.Invite7", "maybe an other time", false);
            SetDefault("AIMLBot.Invite8", "Need to farm now, sry", false);
            SetDefault("AIMLBot.Invite9", "I am about to log", false);
            SetDefault("AIMLBot.Invite10", "", false);
            SetDefault("AIMLBot.Invite11", "", false);
            SetDefault("AIMLBot.Invite12", "", false);
            SetDefault("AIMLBot.Invite13", "", false);
            SetDefault("AIMLBot.Invite14", "", false);
            SetDefault("AIMLBot.Invite15", "", false);
            SetDefault("AIMLBot.Invite16", "", false);
            SetDefault("AIMLBot.Invite17", "", false);
            SetDefault("AIMLBot.Invite18", "", false);
            SetDefault("AIMLBot.Invite19", "", false);
            SetDefault("AIMLBot.Invite20", "", false);

            SetDefault("AIMLBot.Opening1", "hi", false);
            SetDefault("AIMLBot.Opening2", "hello ##", false);
            SetDefault("AIMLBot.Opening3", "hi there", false);
            SetDefault("AIMLBot.Opening4", "Hello", false);
            SetDefault("AIMLBot.Opening5", "Hi", false);
            SetDefault("AIMLBot.Opening6", "Whats up", false);
            SetDefault("AIMLBot.Opening7", "What your doing?", false);
            SetDefault("AIMLBot.Opening8", "hello", false);
            SetDefault("AIMLBot.Opening9", "Hi ## what your doing", false);
            SetDefault("AIMLBot.Opening10", "hi ##", false);
            SetDefault("AIMLBot.Opening11", "", false);
            SetDefault("AIMLBot.Opening12", "", false);
            SetDefault("AIMLBot.Opening13", "", false);
            SetDefault("AIMLBot.Opening14", "", false);
            SetDefault("AIMLBot.Opening15", "", false);
            SetDefault("AIMLBot.Opening16", "", false);
            SetDefault("AIMLBot.Opening17", "", false);
            SetDefault("AIMLBot.Opening18", "", false);
            SetDefault("AIMLBot.Opening19", "", false);
            SetDefault("AIMLBot.Opening20", "", false);

            SetDefault("AIMLBot.BG1", "WTF", false);
            SetDefault("AIMLBot.BG2", "OMG", false);
            SetDefault("AIMLBot.BG3", "Yhea !", false);
            SetDefault("AIMLBot.BG4", "Come on", false);
            SetDefault("AIMLBot.BG5", "Damn horde", false);
            SetDefault("AIMLBot.BG6", "WTF!", false);
            SetDefault("AIMLBot.BG7", "omw", false);
            SetDefault("AIMLBot.BG8", "", false);
            SetDefault("AIMLBot.BG9", "", false);
            SetDefault("AIMLBot.BG10", "", false);
            SetDefault("AIMLBot.BG11", "", false);
            SetDefault("AIMLBot.BG12", "", false);
            SetDefault("AIMLBot.BG13", "", false);
            SetDefault("AIMLBot.BG14", "", false);
            SetDefault("AIMLBot.BG15", "", false);
            SetDefault("AIMLBot.BG16", "", false);
            SetDefault("AIMLBot.BG17", "", false);
            SetDefault("AIMLBot.BG18", "", false);
            SetDefault("AIMLBot.BG19", "", false);
            SetDefault("AIMLBot.BG20", "", false);

            SetDefault("AIMLBot.BGpos1", "Yhes", false);
            SetDefault("AIMLBot.BGpos2", "You go man", false);
            SetDefault("AIMLBot.BGpos3", "Maybe we win this time", false);
            SetDefault("AIMLBot.BGpos4", "well done", false);
            SetDefault("AIMLBot.BGpos5", "good one", false);
            SetDefault("AIMLBot.BGpos6", "", false);
            SetDefault("AIMLBot.BGpos7", "", false);
            SetDefault("AIMLBot.BGpos8", "", false);
            SetDefault("AIMLBot.BGpos9", "", false);
            SetDefault("AIMLBot.BGpos10", "", false);

            SetDefault("AIMLBot.BGneg1", "O no", false);
            SetDefault("AIMLBot.BGneg2", "Damn", false);
            SetDefault("AIMLBot.BGneg3", "Come on, defend", false);
            SetDefault("AIMLBot.BGneg4", "I am losing all day", false);
            SetDefault("AIMLBot.BGneg5", "we need to organise", false);
            SetDefault("AIMLBot.BGneg6", "", false);
            SetDefault("AIMLBot.BGneg7", "", false);
            SetDefault("AIMLBot.BGneg8", "", false);
            SetDefault("AIMLBot.BGneg9", "", false);
            SetDefault("AIMLBot.BGneg10", "", false);

            SetDefault("AIMLBot.Duel1", "no, thx man", false);
            SetDefault("AIMLBot.Duel2", "You win anyway, I am not waiting my time to confirm that", false);
            SetDefault("AIMLBot.Duel3", "I don\'t like to duel", false);
            SetDefault("AIMLBot.Duel4", "Sorry maybe one other time", false);
            SetDefault("AIMLBot.Duel5", "Not now, sorry", false);
            SetDefault("AIMLBot.Duel6", "Not interested in duelling", false);
            SetDefault("AIMLBot.Duel7", "I am busy sorry", false);
            SetDefault("AIMLBot.Duel8", "Don't fancy the aggression", false);
            SetDefault("AIMLBot.Duel9", "Prefer not to fight other human players", false);
            SetDefault("AIMLBot.Duel10", "No thank you.", false);
            SetDefault("AIMLBot.Duel11", "", false);
            SetDefault("AIMLBot.Duel12", "", false);
            SetDefault("AIMLBot.Duel13", "", false);
            SetDefault("AIMLBot.Duel14", "", false);
            SetDefault("AIMLBot.Duel15", "", false);
            SetDefault("AIMLBot.Duel16", "", false);
            SetDefault("AIMLBot.Duel17", "", false);
            SetDefault("AIMLBot.Duel18", "", false);
            SetDefault("AIMLBot.Duel19", "", false);
            SetDefault("AIMLBot.Duel20", "", false);

            SetDefault("AIMLBot.WLEmail", "aiml@example.com", false);
            SetDefault("AIMLBot.WLPass", "", false);
            SetDefault("AIMLBot.RemEmail", "yourWL@example.com", false);
            SetDefault("AIMLBot.MaxInvite", "3", false);
            SetDefault("AIMLBot.MaxInviteMsg", "Leave me alone, consider yourself ignored", false);
            SetDefault("AIMLBot.MaxWords", "14", false);
            SetDefault("AIMLBot.AIMLfeedback", "True", false);
            SetDefault("AIMLBot.AIMLuse", "True", false);
            SetDefault("AIMLBot.BGEventUse", "True", false);
            SetDefault("AIMLBot.BGEventLikelihood", "40", false);
            SetDefault("AIMLBot.LookDelay", "30", false);

            SetDefault("AIMLBot.UseDuel", "True", false);
        }

        public static void GetSettings()                                        // Load settings (First store defaults, none overwrite)
        {
            AIMLBOTLog("Loading Settings");
            CreateDefaultConfig();
            StopGliding = GContext.Main.GetConfigBool("AIMLBot.StopGlide");
            AvoidSelfLoop = GContext.Main.GetConfigBool("AIMLBot.StopLoop");
            CharDelay = GContext.Main.GetConfigInt("AIMLBot.CharDelay");
            RandomMove = GContext.Main.GetConfigBool("AIMLBot.RandomMove");
            JumpLikelihood = GContext.Main.GetConfigInt("AIMLBot.JumpLike");
            SendDefault = GContext.Main.GetConfigBool("AIMLBot.DWhisper");
            GM_Reply_on = GContext.Main.GetConfigBool("AIMLBot.GMReply");
            GM_Reply = GContext.Main.GetConfigString("AIMLBot.GMWhisper");
            UseBlacklist = GContext.Main.GetConfigBool("AIMLBot.UseBlacklist");
            MaxBlacklistCount = GContext.Main.GetConfigInt("AIMLBot.MaxBlacklistCount");
            AppriciatHeal = GContext.Main.GetConfigBool("AIMLBot.TYHeal");
            AppriciatBuff = GContext.Main.GetConfigBool("AIMLBot.TYBuff");
            MaxGrayListCount = GContext.Main.GetConfigInt("AIMLBot.MaxGraylistCount");
            AppriciatTimer = new GSpellTimer(GContext.Main.GetConfigInt("AIMLBot.TYTime") * 60 * 1000, true);
            UseFace = GContext.Main.GetConfigBool("AIMLBot.UseFace");
            UseSay = GContext.Main.GetConfigBool("AIMLBot.UseSay");
            UseWhisper = GContext.Main.GetConfigBool("AIMLBot.UseWhisper"); 
            triger1 = GContext.Main.GetConfigString("AIMLBot.Keyword1");
            triger2 = GContext.Main.GetConfigString("AIMLBot.Keyword2");
            triger3 = GContext.Main.GetConfigString("AIMLBot.Keyword3");
            triger4 = GContext.Main.GetConfigString("AIMLBot.Keyword4");
            UseMisspell = GContext.Main.GetConfigBool("AIMLBot.UseMisspell");
            misspellLikelihood = GContext.Main.GetConfigInt("AIMLBot.MisspellLikelihood");
            UseMisspellCorrection = GContext.Main.GetConfigBool("AIMLBot.UseMisspellCorrection");
            CleanMessageSendTimer = new GSpellTimer(GContext.Main.GetConfigInt("AIMLBot.MSGTime") * 60 * 1000, false);
            UseInvite = GContext.Main.GetConfigBool("AIMLBot.UseInvite");
            UseInitiateChat = GContext.Main.GetConfigBool("AIMLBot.UseInitiate");
            VeryCloseDistance = GContext.Main.GetConfigInt("AIMLBot.InitiateDistance");
            CloseDistance = GContext.Main.GetConfigInt("AIMLBot.LookForCloseDistance");
            UseRemoveDot = GContext.Main.GetConfigBool("AIMLBot.UseRemoveDot");
            UseEmote = GContext.Main.GetConfigBool("AIMLBot.UseEmote");
            UseDuel = GContext.Main.GetConfigBool("AIMLBot.UseDuel");

            AIMLfeedback = GContext.Main.GetConfigBool("AIMLBot.AIMLfeedback");  

            MaxWords = GContext.Main.GetConfigInt("AIMLBot.MaxWords");
            
            InviteMax = GContext.Main.GetConfigInt("AIMLBot.MaxInvite");
            InviteMaxMessage = GContext.Main.GetConfigString("AIMLBot.MaxInviteMsg");    

            BGTimer = new GSpellTimer(GContext.Main.GetConfigInt("AIMLBot.BGTime") * 1000, false); ;
            UseBGChat = GContext.Main.GetConfigBool("AIMLBot.UseBGchat");

            BGEventsUse = GContext.Main.GetConfigBool("AIMLBot.BGEventUse");
            BGEventsLikelihood = GContext.Main.GetConfigInt("AIMLBot.BGEventLikelihood");

            LookingTime = GContext.Main.GetConfigInt("AIMLBot.LookDelay") * 1000;

            if (triger1.Length <= 1) triger1 = GContext.Main.GetRandomString();
            if (triger2.Length <= 1) triger2 = GContext.Main.GetRandomString();
            if (triger3.Length <= 1) triger3 = GContext.Main.GetRandomString();
            if (triger4.Length <= 1) triger4 = GContext.Main.GetRandomString();

            for (int i = 1; i <= 20 ; i++)
            {
                string tmp = GContext.Main.GetConfigString("AIMLBot.Appriciation" + i);
                if (tmp.Length >= 1 && tmp != ChatBot.EmplyReplacement) Appriciation.Add(tmp);
            }

            for (int i = 1; i <= 20; i++)
            {
                string tmp = GContext.Main.GetConfigString("AIMLBot.Correction" + i);
                if (tmp.Length >= 1 && tmp != ChatBot.EmplyReplacement) Correction.Add(tmp);
            }

            for (int i = 1; i <= 20; i++)
            {
                string tmp = GContext.Main.GetConfigString("AIMLBot.Invite" + i);
                if (tmp.Length >= 1 && tmp != ChatBot.EmplyReplacement) Invite.Add(tmp);
            }

            for (int i = 1; i <= 20; i++)
            {
                string tmp = GContext.Main.GetConfigString("AIMLBot.Opening" + i);
                if (tmp.Length >= 1 && tmp != ChatBot.EmplyReplacement) Opening.Add(tmp);
            }

            for (int i = 1; i <= 20; i++)
            {
                string tmp = GContext.Main.GetConfigString("AIMLBot.BG" + i);
                if (tmp.Length >= 1 && tmp != ChatBot.EmplyReplacement) BG.Add(tmp);
            }

            for (int i = 1; i <= 10; i++)
            {
                string tmp = GContext.Main.GetConfigString("AIMLBot.BGpos" + i);
                if (tmp.Length >= 1 && tmp != ChatBot.EmplyReplacement) BGpositive.Add(tmp);
            }

            for (int i = 1; i <= 10; i++)
            {
                string tmp = GContext.Main.GetConfigString("AIMLBot.BGneg" + i);
                if (tmp.Length >= 1 && tmp != ChatBot.EmplyReplacement) BGnegative.Add(tmp);
            }

            for (int i = 1; i <= 20; i++)
            {
                string tmp = GContext.Main.GetConfigString("AIMLBot.Duel" + i);
                if (tmp.Length >= 1 && tmp != ChatBot.EmplyReplacement) Duel.Add(tmp);
            }

            for (int i = 1; i <= 4; i++)
            {
                string tmp = GContext.Main.GetConfigString("AIMLBot.DReply" + i);
                if (tmp.Length >= 1 && tmp != ChatBot.EmplyReplacement) DefaultMesg.Add(tmp);
            }

        }

        //---------------------------------------Start Up stuff---------------------------------------------

        public static Bot myBot = new Bot();                                    // Make the AIMLbot class

        public static User myUser = new User("Default", myBot);                 // Make the AIML bot remote user

        public static Random RandomClass = new Random();                        // Make a random class

        public static void Loader()                                             // Starting AIMLBot
        {

            AIMLBOTLog(Version + "  is loading");

            if (!File.Exists(AppDomain.CurrentDomain.BaseDirectory + "Classes\\AIMLbot4Glider\\AIMLbot.log")) StartHelpFile();

            CleanLog();

            MonitorBox.Text = GContext.Main.GetRandomString();

            GetSettings();
            MonitorBox.Show();

            myBot.loadSettings();
            myBot.loadAIMLFromFiles();

            BlackList = Get2DList("Classes\\AIMLbot4Glider\\Blacklist.txt");

            GContext.Main.SetKeyValue("Common.Paste", GBarState.Indifferent, GContext.SS_CTRL, 'v');
            GContext.Main.SetKeyValue("Common.Return", GBarState.Indifferent, GContext.SS_NONE, 13);
            GContext.Main.SetKeyValue("Common.Backspace", GBarState.Indifferent, GContext.SS_NONE, 8);

            GContext.Main.ChatLog += new GContext.GChatLogHandler(Read_ChatLog);
            GContext.Main.CombatLog += new GContext.GCombatLogHandler(Read_CombatLog);

            GetCurrent();

            AIMLBOTLog("Loading done", false);
        }

        public static void GetForum(MonitorBox1 Get)                            // Get the ChatLog (Textbox) element to this class
        {
            MonitorLog = Get;
        }

        public static void UnLoader()                                           // Stopping AIMLBot
        {
            AIMLBOTLog(Version + " is unloading", false);
            GContext.Main.ChatLog -= new GContext.GChatLogHandler(Read_ChatLog);
            GContext.Main.CombatLog -= new GContext.GCombatLogHandler(Read_CombatLog);
            Save2DList(BlackList, "Classes\\AIMLbot4Glider\\Blacklist.txt");

            GContext.Main.SetConfigValue("AIMLBot.PosX", MonitorBox.Location.X.ToString(), true);
            GContext.Main.SetConfigValue("AIMLBot.PosY", MonitorBox.Location.Y.ToString(), true);

            TryIcon = false;
            MonitorBox.Close();

            AIMLBOTLog("Unloading done");
        }

        public static void StartHelpFile()                                      // Showing the help file if no log exists
        {
                System.Diagnostics.Process proc;
                System.Diagnostics.ProcessStartInfo procInfo = new System.Diagnostics.ProcessStartInfo();

                procInfo.UseShellExecute = true;
                procInfo.FileName = AppDomain.CurrentDomain.BaseDirectory + "Classes\\AIMLbot4Glider\\aimlbot help.chm";
                proc = System.Diagnostics.Process.Start(procInfo);
                AIMLBOTLog("Opening help file", true);
        }

        public static void GetCurrent()                                         // Check internet for latest version
        {
            XmlTextReader reader;
            try {
                reader = new XmlTextReader("http://aimbot.webhop.net/Current.xml");

                string CurrentElementName = "";
                string DouwnloadURL = "";
                bool CoreOnly = false;

                while (reader.Read())
                {
                    if (reader.Name == "Number" && reader.Value == "105") AIMLBOTLog("This is the latest version");
                    switch (reader.NodeType)
                    {
                        case XmlNodeType.Element: // The node is an element.
                            CurrentElementName = reader.Name;
                            break;

                        case XmlNodeType.Text: //Display the text in each element.
                            if (CurrentElementName == "URL") DouwnloadURL = reader.Value;
                            if (CurrentElementName == "CoreOnly")
                            {
                                if (reader.Value == "True") CoreOnly = true;
                            }
                            if (CurrentElementName == "Number")
                            {
                                if (reader.Value != VersionStr)
                                {

                                    if (CoreOnly)
                                    {
                                        MessageBoxButtons buttons = MessageBoxButtons.YesNo;
                                        DialogResult result;

                                        result = MessageBox.Show(MonitorBox, "This is not the latest version of AIMLbot4Glider, would you like to start the auto updater now?", GContext.Main.GetRandomString(), buttons, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1);

                                        if (result == DialogResult.Yes)
                                        {
                                            System.Diagnostics.Process proc;
                                            System.Diagnostics.ProcessStartInfo procInfo = new System.Diagnostics.ProcessStartInfo();

                                            procInfo.UseShellExecute = true;
                                            procInfo.FileName = AppDomain.CurrentDomain.BaseDirectory + "Classes\\AIMLbot4Glider\\AIMLbot4Glider Updater.exe";
                                            proc = System.Diagnostics.Process.Start(procInfo);
                                            AIMLBOTLog("Startring Updater", true);

                                             // I Need To exit Glider here, somehow  !!!  At the moment it is a manual step.
                                        }
                                    }
                                    else
                                    {
                                        MessageBoxButtons buttons = MessageBoxButtons.YesNo;
                                        DialogResult result;

                                        result = MessageBox.Show(MonitorBox, "This is not the latest version of AIMLbot4Glider, the latest version cannot be updated automatically, would you like to download it now manually?", GContext.Main.GetRandomString(), buttons, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1);

                                        if (result == DialogResult.Yes)
                                        {
                                            System.Diagnostics.Process.Start(DouwnloadURL);
                                        }
                                    }
                                }
                                else AIMLBOTLog("You are running the latest version");
                            }
                            break;
                    }
                }
            } catch (Exception e)
            {
                AIMLBOTLog("Could not get the latest version info, " + e.Message + ", see the logfile for more details");
                AIMLBOTLog("##>> your AIMLbot4Glider might be outdated <<##");
                AIMLBOTLog(e.ToString(), true);
            } 
        }

        public static void GetLatestAIML()                                      // Check files.xml for all files
        {
            string DoneMessage = "You will now download the latest AIML files from the server, do not close AIMLbot4Glider or Glider during this process";
            AIMLBOTLog(DoneMessage);
            MessageBoxButtons buttons = MessageBoxButtons.OKCancel;
            DialogResult result;
            result = MessageBox.Show(MonitorBox, DoneMessage, "Updater", buttons, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1);

            if (result == DialogResult.Cancel)
            {
                AIMLBOTLog("You cancelled the download request.", true);
                return;
            }

            RemainingFiles = 0;

            string CurrentElement = "";
            XmlTextReader reader;
            try
            {
                reader = new XmlTextReader("http://aimbot.webhop.net/AIML/files.xml");

                while (reader.Read())
                {
                    if (reader.NodeType == XmlNodeType.Element) CurrentElement = reader.Name;
                    if (reader.NodeType == XmlNodeType.Text && CurrentElement == "file") 
                    {
                        RemainingFiles++;
                        DownloadAIMLFile(reader.Value);
                    }
                }

            }
            catch (Exception e)
            {

                DoneMessage = "Could not get the latest AIML files from the server " + e.Message + ", see the logfile for details.";
                AIMLBOTLog(DoneMessage);
                buttons = MessageBoxButtons.OK;
                result = MessageBox.Show(MonitorBox, DoneMessage, "Updater", buttons, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1);
                RemainingFiles = 0;
                AIMLBOTLog(e.ToString(), true);
            }

        }

        public static void DownloadAIMLFile(string FileName)                    // Download new AIML files
        {
            string FullPath = AppDomain.CurrentDomain.BaseDirectory + "Classes\\AIMLbot4Glider\\aiml\\" + FileName;
            string AIMLURL = "http://aimbot.webhop.net/AIML/" + FileName;

            AIMLBOTLog("Downloading new " + FileName);
 
            try
            {
                WebClient client = new WebClient();
                Uri uri = new Uri(AIMLURL);
                client.DownloadFileAsync(uri, FullPath);
                client.DownloadFileCompleted += new AsyncCompletedEventHandler(OneFileCompleated);
            }
            catch (WebException exc)
            {
                AIMLBOTLog(exc.Message.ToString(), true);
            }
            catch (UriFormatException exc)
            {
                AIMLBOTLog(exc.Message.ToString(), true);
            }
        }

        private static void OneFileCompleated(object sender, AsyncCompletedEventArgs e)
        {
            AIMLBOTLog(RemainingFiles + " files left to download, don\'t close Glider or AIMLbot4Glider");

            if (RemainingFiles <= 1)
            {
                string DoneMessage = "New AIML files are now downloaded and will now be loaded.";
                AIMLBOTLog(DoneMessage);
                MessageBoxButtons buttons = MessageBoxButtons.OK;
                DialogResult result;
                result = MessageBox.Show(MonitorBox, DoneMessage, "Updater", buttons, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1);
                RemainingFiles = 0;
                ChatBot.AIMLBOTLog("Loading AIML files.", true);
                ChatBot.myBot.loadAIMLFromFiles();
            }
            else
            {
                RemainingFiles--;
            }

        }

        //------------------------------------Monitoring the Log's------------------------------------------

        public static void Read_CombatLog(string RawTextOriginal)               // Monitoring the Combatlog
        {
            if (RawTextOriginal == null || RawTextOriginal == "") return;

            #region Dings
            if (GContext.Main.Me.Level > LatestLVL)
            {
                if (SetLevel)
                {
                    MSNmessage = "DING !!! (" + GContext.Main.Me.Level + ")";
                    AIMLBotChatLog("DING !!! (" + GContext.Main.Me.Level + ")");
                }
                SetLevel = true;
                LatestLVL = GContext.Main.Me.Level;
            }
            #endregion

            #region Change dynamic AIML tags
            if (GContext.Main.IsGliding)
            {
                string race = GContext.Main.Me.PlayerRace.ToString();

                ChatBot.myBot.GlobalSettings.addSetting("name", GContext.Main.Me.Name);

                if (GContext.Main.IsGliding)
                {
                    switch (race.ToLower())
                    {
                        case "nightelf":
                            myBot.GlobalSettings.addSetting("birthplace", "Darnassus");
                            break;
                        case "gnome":
                        case "dwarf":
                            myBot.GlobalSettings.addSetting("birthplace", "Dun Morogh");
                            break;
                        case "human":
                            myBot.GlobalSettings.addSetting("birthplace", "Elwynn Forest");
                            break;
                        case "draenei":
                            myBot.GlobalSettings.addSetting("birthplace", "Kalimdor");
                            break;
                        case "undead":
                            myBot.GlobalSettings.addSetting("birthplace", "Deathknell");
                            break;
                        case "tauren":
                            myBot.GlobalSettings.addSetting("birthplace", "Mulgore");
                            break;
                        case "troll":
                        case "orc":
                            myBot.GlobalSettings.addSetting("birthplace", "Durotar");
                            break;
                        case "bloodelf":
                            myBot.GlobalSettings.addSetting("birthplace", "Eversong Woods");
                            break;
                    }
                }

                if (GContext.Main.IsGliding) ChatBot.myBot.GlobalSettings.addSetting("location", GContext.Main.ZoneText);

                if (PVPfaction(GContext.Main.Me) == 1) ChatBot.myBot.GlobalSettings.addSetting("faction", "alliance");
                if (PVPfaction(GContext.Main.Me) == 2) ChatBot.myBot.GlobalSettings.addSetting("faction", "horde");

                ChatBot.myBot.GlobalSettings.addSetting("level", GContext.Main.Me.Level.ToString());
                ChatBot.myBot.GlobalSettings.addSetting("class", GContext.Main.Me.PlayerClass.ToString());
                ChatBot.myBot.GlobalSettings.addSetting("race", GContext.Main.Me.PlayerRace.ToString());
                ChatBot.myBot.GlobalSettings.addSetting("species", GContext.Main.Me.PlayerRace.ToString());

            }
            
            #endregion

            #region Dead
            if (RawTextOriginal.Contains(GContext.Main.Me.Name + "|h died"))     // example NAME|h died
            {
                DeadCount++;
                AIMLBotChatLog("You died");
                MSNmessage = "You died";
            }
            #endregion

            #region Killed
            // XXXXXXXX|hXXXXXX|h has slain |Hunit:0xF530004E0B19DFB2:Deathforge Technician|hDeathforge Technician|h!
            if (RawTextOriginal.Contains(GContext.Main.Me.Name + "|h has slain"))     // Kills
            {
                KillCount++;
            }
            #endregion

            #region Appricitation
            if (AppriciatTimer.IsReady && GContext.Main.IsGliding && GContext.Main.IsAttached &&
                (AppriciatHeal || AppriciatBuff))
            {
                MyToonName = GContext.Main.Me.Name;

                string CombatText = RawTextOriginal.ToLower();
                string myName = GContext.Main.Me.Name.ToLower();

                if (CombatText.Contains(myName + "|h for ") && CombatText.Contains("heals") &&
                    AppriciatHeal && AppriciatTimer.IsReady) // Did we get a heal ??
                {
                    if (CombatText.Contains("bloodthirst|r heals ") ||
                        CombatText.Contains(myName + "'s|h") ||
                        CombatText.Contains("leader of the pack") ||
                        CombatText.Contains("drain") ||
                        CombatText.Contains("siphon") ||
                        CombatText.Contains("crusader") ||
                        CombatText.Contains("lifestone")
                       ) return;                                                //Don't show apprication on self heal, talents, etc.

                    string HealFrom = CombatText.Substring(2, CombatText.IndexOf("'s|h") - 2);
                    HealFrom = Right(HealFrom, HealFrom.Length - HealFrom.IndexOf("|h") - 2);
                    AIMLBOTLog("Recieved a heal from : " + HealFrom, true);

                    if (CheckPartyMembersClose(HealFrom)) return;

                    if (UseBlacklist && CheckBlackList(HealFrom)) return;

                    CheckWhiteList(HealFrom);

                    AIMLFileLog("Heal RAW text : " + RawTextOriginal);
                    Thread Appriciation = new Thread(new  ThreadStart(SendAppriciation));
                    Appriciation.Start();
                }

                if (CombatText.Contains(myName + "|h gains") &&
                    AppriciatBuff && AppriciatTimer.IsReady)  // Did we get a Buff ??
                {
                    string MyClass = GContext.Main.Me.PlayerClass.ToString();

                    if (
                        CombatText.Contains("blessing of kings") && MyClass != "Paladin" ||
                        CombatText.Contains("blessing of might") && MyClass != "Paladin" ||
                        CombatText.Contains("blessing of light") && MyClass != "Paladin" ||
                        CombatText.Contains("blessing of salvation") && MyClass != "Paladin" ||
                        CombatText.Contains("blessing of wisdom") && MyClass != "Paladin" ||
                        CombatText.Contains("blessing of sanctuary") && MyClass != "Paladin" ||
                        CombatText.Contains("arcane intellect") && MyClass != "Mage" ||
                        CombatText.Contains("thorns") && MyClass != "Druid" ||
                        CombatText.Contains("mark of the wild") && MyClass != "Druid" ||
                        CombatText.Contains("rejuvenation") && MyClass != "Druid" ||
                        CombatText.Contains("lifebloom") && MyClass != "Druid" ||
                        CombatText.Contains("power word: fortitude") && MyClass != "Priest" ||
                        CombatText.Contains("divine Spirit") && MyClass != "Priest" ||
                        //CombatText.Contains("stealth") && MyClass == "Rogue" ||       //Testline
                        CombatText.Contains("unending breath") && MyClass != "Warlock"
                       )
                    {
                        AIMLFileLog("Buff RAW text : " + RawTextOriginal);
                        Thread Appriciation = new Thread(new ThreadStart(SendAppriciation));
                        Appriciation.Start();
                    }
                }
            }
            #endregion

            Thread CheckPlayers = new Thread(new ThreadStart(CheckPlayerClose));
            CheckPlayers.Start();
        }

        public static void Read_ChatLog(string RawChatText, string ParsedText)  // Monitoring the Chatlog
        {
            if (RawChatText == null || RawChatText == "") return;
            if (ParsedText == null || ParsedText == "") return;

            string LowerText = ParsedText.ToLower();

            #region GM
            if (ParsedText.Contains(GM_Indentifyer) && GContext.Main.IsGliding && GM_Reply_on)	// Did we get a GM wisper during gliding??
            {
                // GM whisper example : |TInterface\ChatFrame\UI-ChatIcon-Blizz.blp:0:2:0:-3|t [**GM_Name**] whispers: Excellent. Farewell ******, and have a lovely evening! :)

                AIMLBOTLog("Please post this line > " + ParsedText);
                AIMLBOTLog("here : http://vforums.mmoglider.com/showthread.php?t=169301");
                string From = ParsedText.Substring(GMNameStartPosition, ParsedText.IndexOf(whisper_indentifyer) - 1);
                MSNmessage = ("GM message from : " + From);
                LastFrom = From;
                Thread GMACTION = new Thread(new ThreadStart(GM_Panic));
                GMACTION.Priority = ThreadPriority.Highest;
                GMACTION.Start();
                return;
            }
            #endregion

            #region BGevents
            if (BGEventsUse && RandomClass.Next(1, 101) <= BGEventsLikelihood && GContext.Main.IsGliding)
            {                                                                       // Positive for horde
                if (LowerText.Contains("the horde flag was returned to its base") ||
                    LowerText.Contains("the stormpike aid station is under attack") ||
                    LowerText.Contains("soldiers of stormpike, your general is under attack") ||
                    LowerText.Contains("the horde has taken the") ||
                    LowerText.Contains("if left unchallenged, the horde will control it in") ||
                    LowerText.Contains("the horde has gathered 1800 resources, and is near victory") ||
                    LowerText.Contains("the horde has taken control of the") ||
                    LowerText.Contains("the alliance has lost control of the ") ||
                    LowerText.Contains("the horde have captured the flag")
                   )
                {
                    if (LowerText.Contains("farm") ||
                        LowerText.Contains("stable")
                       ) return;

                    if (PVPfaction(GContext.Main.Me) == 2)                          // If I am Horde
                    {
                        AIMLBOTLog("Positive BG event happend", true);
                        Thread BGPos = new Thread(new ThreadStart(SendBGPositive));
                        BGPos.Start();
                        return;
                    }
                    else                                                            // I am not horde
                    {
                        AIMLBOTLog("Negative BG event happend", true);
                        Thread BGNeg = new Thread(new ThreadStart(SendBGNegative));
                        BGNeg.Start();
                        return;
                    }
                }
                                                                                    // Positive for Alliance
                if (LowerText.Contains("the alliance flag was returned to its base") ||
                    LowerText.Contains("was taken by the alliance") ||
                    LowerText.Contains("thar yells: stormpike filth! In my keep?!") ||
                    LowerText.Contains("the frostwolf relieft hut was taken by the alliance") ||
                    LowerText.Contains("the stormpike clan bows to no one, especially horde") ||
                    LowerText.Contains("the alliance has taken the ") ||
                    LowerText.Contains("if left unchallenged, the alliance will control it in") ||
                    LowerText.Contains("the alliance has gathered 1800 resources, and is near victory") ||
                    LowerText.Contains("the alliance has taken control of the") ||
                    LowerText.Contains("the horde has lost control of the ") ||
                    LowerText.Contains("the alliance have captured the flag")
                   )
                {

                    if (LowerText.Contains("farm") ||
                        LowerText.Contains("stable")
                       ) return;

                    if (PVPfaction(GContext.Main.Me) == 1)                          // If I am Alliance
                    {
                        AIMLBOTLog("Positive BG event happend", true);
                        Thread BGPos = new Thread(new ThreadStart(SendBGPositive));
                        BGPos.Start();
                        return;
                    }
                    else                                                            // I am not Alliance
                    {
                        AIMLBOTLog("Negative BG event happend", true);
                        Thread BGNeg = new Thread(new ThreadStart(SendBGNegative));
                        BGNeg.Start();
                        return;
                    }
                }
            }

            #endregion

            #region GuildChat
            if (MSNguild)	                                                                    // Did someone say someting in the guild?
            {
                if (RawChatText.Contains(Guild_indentifyer) &&
                    !RawChatText.Contains(Guild_indentifyer + GContext.Main.Me.Name))
                    MSNmessage = (ParsedText);
            }
            #endregion

            #region BGRandom
            if (ParsedText.Contains(BG_indentifyer) && GContext.Main.IsGliding && UseBGChat)	// Did someone say someting in BG?
            {
                if (ParsedText.Contains("[" + GContext.Main.Me.Name + "]")) return;

                if (MSNbg) MSNmessage = (ParsedText);

                if (LowerText.Contains(GContext.Main.Me.Name.ToLower()) && (
                    LowerText.Contains("report") || LowerText.Contains("afk") ||
                    LowerText.Contains("repord") || LowerText.Contains("bot")
                   ))
                {
                    MSNmessage = ("People are talking about me" + Environment.NewLine + ParsedText);
                    AIMLBOTLog("People are talking about me, ignore timer", true);
                    AIMLFileLog("RAW : " + ParsedText);
                    Thread SendBG = new Thread(new ThreadStart(SendBGChat));
                    SendBG.Start();
                    BGTimer.Reset();
                    return;
                }

                if (BGTimer.IsReady)
                {
                    Thread SendBG = new Thread(new ThreadStart(SendBGChat));
                    SendBG.Start();
                    BGTimer.Reset();
                    return;
                }
            }

            if (LowerText.Contains("the battle") && LowerText.Contains("has begun"))            // Did a BG Begun
            {
                BGCount++;
                AIMLBOTLog("Battleground has begun, resetting timer", true);
                MSNmessage = ("New BG started");
                BGTimer.Reset();
                return;
            }

            #endregion

            #region Inviters
            //Group invite example [**Player**] has invited you to join a group.

            if (ParsedText.Contains(invite_indentifyer) && UseInvite && GContext.Main.IsGliding) // Did we get an invite during gliding?
            {
                string From = ParsedText.Substring(InviteNameStartPosition, ParsedText.IndexOf(invite_indentifyer) - 1);
                AIMLBOTLog("[" + From + "] has invited you", false);

                if (!AIMLautoanswer)
                {
                    AIMLBOTLog("AIML autoanswer is off, do nothing", true);
                    return;
                }

                if (CheckPartyMembersClose(From))
                {
                    AIMLBOTLog(From + " is a party member close, do nothing", true);
                    return;
                }


                if (CheckBlackList(From))
                {
                    AIMLBOTLog(From + " is on the blacklist, do nothing", true);
                    return;
                }

                if (LastInviteFrom == From) LastInviteCount++; else LastInviteCount = 0;
                if (LastInviteCount >= InviteMax)
                {
                    LastInviteCount = 0;
                    SendMessage = InviteMaxMessage;
                    MSNmessage = ("[" + From + "] has invited you (Last time)");
                    LastFrom = From;
                    Thread SendLastW = new Thread(new ThreadStart(SendWisper));
                    SendLastW.Start();
                    AddBlackList(From);
                    return;
                }

                LastInviteFrom = From;

                if (!CheckWhiteList(From)) AddWhiteList(From);
                string Message = Invite[RandomClass.Next(0, Invite.Count)].ToString();
                MSNmessage = ("[" + From + "] has invited you");
                LastFrom = From;
                SendMessage = Message;
                Thread SendW = new Thread(new ThreadStart(SendWisper));
                SendW.Start();
                return;
            }
            #endregion

            #region Duel 
            // AutoDecline: Duel challenge from xxxxxxxxxx was declined.
            if (LowerText.Contains(duel_indentifyer.ToLower()) && UseDuel && GContext.Main.IsGliding)
            {
                //AIMLBOTLog("DEBUG : " + LowerText, false);
                string From = LowerText.Substring(duel_indentifyer.Length, LowerText.Length - duel_indentifyer.Length);

                From = From.Substring(0, From.IndexOf(' '));

                AIMLBOTLog("Duel request from : " + From);
                MSNmessage = ("Duel request from : " + From);
                
                if (!AIMLautoanswer) return;
                if (CheckPartyMembersClose(From)) return;
                if (CheckBlackList(From))
                {
                    AIMLBOTLog(From + " is on the blacklist, do nothing", true);
                    return;
                }

                if (!CheckWhiteList(From)) AddWhiteList(From);

                // Send whisper to From...
                string Message = Duel[RandomClass.Next(0, Duel.Count)].ToString();

                AIMLBOTLog("DEBUG send: " + Message + " to: " +From);

                LastFrom = From;
                SendMessage = Message;
                Thread SendW = new Thread(new ThreadStart(SendWisper));
                SendW.Start();
                return;

            }
            #endregion

            #region Say
            if (ParsedText.Contains(say_indentifyer) && GContext.Main.IsGliding) // Did someone say someting during gliding?
            {

                int Position = ParsedText.IndexOf(say_indentifyer) + say_indentifyer.Length;
                int MessageLength = ParsedText.Length - Position;

                string Message = ParsedText.Substring(Position, MessageLength);
                string From = ParsedText.Substring(NameStartPosition, ParsedText.IndexOf(say_indentifyer) - 1);

                if (ParsedText.Contains(AFKflag)) From = ParsedText.Substring(NameStartPosition + AFKflag.Length, ParsedText.IndexOf(whisper_indentifyer) - AFKflag.Length - 1);
                if (ParsedText.Contains(DNDflag)) From = ParsedText.Substring(NameStartPosition + DNDflag.Length, ParsedText.IndexOf(whisper_indentifyer) - DNDflag.Length - 1);

                if (From == GContext.Main.Me.Name) return;

                AIMLBotChatLog("[" + From + "] says: " + Message);
                MSNmessage = ("[" + From + "] says: " + Message);

                if (!UseSay)
                {
                    AIMLBOTLog("Say option is off", true);
                    return;
                }

                if (!GeneralCheck(From, Message)) return;

                if (!StringToGunitClose(From).IsPlayer)
                {
                    AIMLBOTLog(From + " is no player, scripted NPC?", true);
                    AddBlackList(From);
                    return;
                }

                string LowerTextMessage = Message.ToLower();

                if (CheckWhiteList(From) ||
                    (NuberOfClosePlayers() == 1) ||
                    LowerTextMessage.Contains(GContext.Main.Me.Name.ToLower()) ||
                    LowerTextMessage.Contains(triger1.ToLower()) ||
                    LowerTextMessage.Contains(triger2.ToLower()) ||
                    LowerTextMessage.Contains(triger3.ToLower()) ||
                    LowerTextMessage.Contains(triger4.ToLower())
                   )
                {
                    if (!CheckWhiteList(From)) AddWhiteList(From);
                    LastFrom = From;
                    SendMessage = MakeAnswer(From, Message);
                    if (SendMessage.Length <= 1 && AIMLfeedback) Feedback.Send(Message);
                    Thread SendW = new Thread(new ThreadStart(SendWisper));
                    SendW.Start();
                    return;
                }
            }
            #endregion

            #region Whispers
            if (ParsedText.Contains(whisper_indentifyer) && GContext.Main.IsGliding) // Did we get a wisper during gliding??
            {
                //Whisper example : [**Player**] whispers: hello.

                int Position = ParsedText.IndexOf(whisper_indentifyer) + whisper_indentifyer.Length;
                int MessageLength = ParsedText.Length - Position;

                string Message = ParsedText.Substring(Position, MessageLength);
                string From = ParsedText.Substring(NameStartPosition, ParsedText.IndexOf(whisper_indentifyer) - 1);

                if (ParsedText.Contains(AFKflag)) From = ParsedText.Substring(NameStartPosition + AFKflag.Length, ParsedText.IndexOf(whisper_indentifyer) - AFKflag.Length - 1);
                if (ParsedText.Contains(DNDflag)) From = ParsedText.Substring(NameStartPosition + DNDflag.Length, ParsedText.IndexOf(whisper_indentifyer) - DNDflag.Length - 1);

                AIMLBotChatLog("[" + From + "] whispers: " + Message);

                if (!UseWhisper)
                {
                    AIMLBOTLog("Whisper option is off", true);
                    return;
                }

                if (!GeneralCheck(From, Message)) return;
                
                if ((From != GContext.Main.Me.Name) || !AvoidSelfLoop)
                {
                    LastFrom = From;
                    SendMessage = MakeAnswer(From, Message);
                    if (SendMessage.Length <= 1 && AIMLfeedback) Feedback.Send(Message);
                    AIMLBOTLog("Starting up answering sequence as a new thread", true);
                    Thread SendW = new Thread(new ThreadStart(SendWisper));
                    SendW.Start();
                    return;
                }
                else
                {
                    AIMLBOTLog("Avoid wispering myself loop");
                    return;
                }
            }
            #endregion
        }

        //----------------------------------------AIMLBot code----------------------------------------------

        public static bool GeneralCheck(string From, string Message)            // Checks it is doing all the time
        {
                if (From == ManualChatWith)
                {
                    AIMLBOTLog(From + " is marked for a manual chat only");
                    ManualMessage = Message;
                    return false;
                }
                else MSNmessage = ("[" + From + "] whispers: " + Message);

                if (WordCount(Message) >= MaxWords)
                {
                    AIMLBOTLog("Message has too much words in it, skip it", true);
                    return false;
                }

                if (!AIMLautoanswer)
                {
                    AIMLBOTLog("AIML autoanswer is off, do nothing", true);
                    return false;
                }

                if (CheckPartyMembersClose(From))
                {
                    AIMLBOTLog(From + " is a party member close, do nothing", true);
                    return false;
                }

                if (CheckBlackList(From))
                {
                    AIMLBOTLog(From + " is on the blacklist, do nothing", true);
                    return false;
                }

                return true;
        }

        public static void SendBGPositive()                                     // Send a positive message to BG chat
        {
            OutOfCombatWait(2000);

            if (StopGliding) GContext.Main.KillAction("AIMLbot", false);
            if (RandomMove && StopGliding) RandomJumpOrMove();

            string RNDTYMsg = BGpositive[RandomClass.Next(0, BGpositive.Count)].ToString();
            if (UseMisspell) RNDTYMsg = MisSpelling(RNDTYMsg);

            Thread.Sleep(RandomClass.Next(CharDelay, CharDelay + (CharDelay / 5)) * RNDTYMsg.Length);

            //Interface.SendLine(SayCommand + RNDTYMsg);
            CopyPasteLine(BGCommand + RNDTYMsg);

            AIMLBotChatLog("[Battleground] [" + GContext.Main.Me.Name + "] : " + RNDTYMsg + " (BG Positive)");
            if (MSNsend) MSNmessage = "[Battleground] [" + GContext.Main.Me.Name + "] : " + RNDTYMsg + " (BG Positive)";

            if ((MisspellCorrection != "") && UseMisspellCorrection)
            {
                string correct = Correction[RandomClass.Next(0, Correction.Count)].ToString();
                correct = correct.Replace("##", MisspellCorrection);
                Thread.Sleep(RandomClass.Next(CharDelay, CharDelay + (CharDelay / 5)) * correct.Length);
                CopyPasteLine(BGCommand + correct);
                AIMLBotChatLog("[Battleground] [" + GContext.Main.Me.Name + "] : " + correct + " (Correction)");
                MisspellCorrection = "";
            }

            if (StopGliding) GContext.Main.StartGlide();
        }

        public static void SendBGNegative()                                     // Send a negative message to BG chat
        {
            OutOfCombatWait(2000);

            if (StopGliding) GContext.Main.KillAction("AIMLbot", false);
            if (RandomMove && StopGliding) RandomJumpOrMove();

            string RNDTYMsg = BGnegative[RandomClass.Next(0, BGnegative.Count)].ToString();
            if (UseMisspell) RNDTYMsg = MisSpelling(RNDTYMsg);

            Thread.Sleep(RandomClass.Next(CharDelay, CharDelay + (CharDelay / 5)) * RNDTYMsg.Length);

            //Interface.SendLine(SayCommand + RNDTYMsg);
            CopyPasteLine(BGCommand + RNDTYMsg);

            AIMLBotChatLog("[Battleground] [" + GContext.Main.Me.Name + "] : " + RNDTYMsg + " (BG Negative)");
            if (MSNsend) MSNmessage = "[Battleground] [" + GContext.Main.Me.Name + "] : " + RNDTYMsg + " (BG Negative)";

            if ((MisspellCorrection != "") && UseMisspellCorrection)
            {
                string correct = Correction[RandomClass.Next(0, Correction.Count)].ToString();
                correct = correct.Replace("##", MisspellCorrection);
                Thread.Sleep(RandomClass.Next(CharDelay, CharDelay + (CharDelay / 5)) * correct.Length);
                CopyPasteLine(BGCommand + correct);
                AIMLBotChatLog("[Battleground] [" + GContext.Main.Me.Name + "] : " + correct + " (Correction)");
                MisspellCorrection = "";
            }

            if (StopGliding) GContext.Main.StartGlide();
        }

        public static void CheckPlayerClose()                                   // Check if somone is looking and trigger action
        {
            if (!GContext.Main.IsAttached) return;
            if (GContext.Main.Me.IsDead) return;
            if (NuberOfClosePlayers() != 1) return;
            if (GContext.Main.ZoneText == "Alterac Valley") return;
            if (GContext.Main.ZoneText == "Arathi Basin") return;
            if (GContext.Main.ZoneText == "Eye of the Storm") return;
            if (GContext.Main.ZoneText == "Warsong Gulch") return;

            GUnit CloseGuy = PlayerLookingClose();

            if (UseInitiateChat && CloseGuy != null && NuberOfClosePlayers() == 1&& //Someone new is looking at me??
                !CheckWhiteList(CloseGuy.Name) && GContext.Main.Me.IsInCombat && !GContext.Main.Me.IsDead && Watching != CloseGuy.Name)
            {
                Watching = CloseGuy.Name;
                AIMLBOTLog(CloseGuy.Name + " is close by and new, check it out!", false);
                Thread.Sleep(LookingTime);
                if (CloseGuy.DistanceToSelf <= VeryCloseDistance && !GContext.Main.Me.IsDead && GContext.Main.IsAttached) 
                    AIMLBOTLog(CloseGuy.Name + " is still close after " + Convert.ToString(VeryCloseDistance/1000) + "seconds!", false);
                SpeakWithHim(CloseGuy);
            }
        }

        public static void OutOfCombatWait(int ms)                              // Wait till I am out of combat
        {
            if (GContext.Main.Me.IsInCombat ) AIMLBOTLog("Waiting to be out of combat", true);

            while (GContext.Main.Me.IsInCombat && !GContext.Main.Me.IsDead && GContext.Main.IsAttached)
            {
                Thread.Sleep(ms);
            }
        }

        public static void SendBGChat()                                         // Send Random text to BG chat
        {
            OutOfCombatWait(2000);

            if (StopGliding) GContext.Main.KillAction("AIMLbot", false);
            if (RandomMove && StopGliding) RandomJumpOrMove();

            string RNDTYMsg = BG[RandomClass.Next(0, BG.Count)].ToString();
            if (UseMisspell) RNDTYMsg = MisSpelling(RNDTYMsg);

            Thread.Sleep(RandomClass.Next(CharDelay, CharDelay + (CharDelay / 5)) * RNDTYMsg.Length);

            //Interface.SendLine(SayCommand + RNDTYMsg);
            CopyPasteLine(BGCommand + RNDTYMsg);
            AIMLBotChatLog("[Battleground][" + GContext.Main.Me.Name + "] : " + RNDTYMsg);
            if (MSNsend) MSNmessage = "[Battleground][" + GContext.Main.Me.Name + "] : " + RNDTYMsg;

            if ((MisspellCorrection != "") && UseMisspellCorrection)
            {
                string correct = Correction[RandomClass.Next(0, Correction.Count)].ToString();
                correct = correct.Replace("##", MisspellCorrection);
                Thread.Sleep(RandomClass.Next(CharDelay, CharDelay + (CharDelay / 5)) * correct.Length);
                CopyPasteLine(BGCommand + correct);
                AIMLBotChatLog("[Battleground][" + GContext.Main.Me.Name + "] says: " + correct + " (Correction)");
                if (MSNsend) MSNmessage = "[Battleground][" + GContext.Main.Me.Name + "] says: " + correct + " (Correction)";
                MisspellCorrection = "";
            }

            if (StopGliding) GContext.Main.StartGlide();
        }

        public static void SendAppriciation()                                   // Send appriciation
        {
            if (!AppriciatTimer.IsReady) return;

            AppriciatTimer.Reset();

            OutOfCombatWait(2000);

            if (GContext.Main.Me.IsDead) return;

            if (StopGliding) GContext.Main.KillAction("AIMLbot", false);
            if (RandomMove && StopGliding) RandomJumpOrMove();

            string RNDTYMsg = Appriciation[RandomClass.Next(0, Appriciation.Count)].ToString();
            if (UseMisspell) RNDTYMsg = MisSpelling(RNDTYMsg);

            Thread.Sleep(RandomClass.Next(CharDelay, CharDelay + (CharDelay / 5)) * RNDTYMsg.Length);

            //Interface.SendLine(SayCommand + RNDTYMsg);
            CopyPasteLine(SayCommand + RNDTYMsg);

            AIMLBotChatLog("[" + GContext.Main.Me.Name + "] says: " + RNDTYMsg + " (appriciation)");
            if (MSNsend) MSNmessage = "[" + GContext.Main.Me.Name + "] says: " + RNDTYMsg + " (appriciation)";

            if ((MisspellCorrection != "") && UseMisspellCorrection)
            {
                string correct = Correction[RandomClass.Next(0, Correction.Count)].ToString();
                correct = correct.Replace("##", MisspellCorrection);
                Thread.Sleep(RandomClass.Next(CharDelay, CharDelay + (CharDelay / 5)) * correct.Length);
                CopyPasteLine(SayCommand + correct);
                AIMLBotChatLog("[" + GContext.Main.Me.Name + "] says: " + correct + " (Correction)");
                MisspellCorrection = "";
            }

            if (StopGliding) GContext.Main.StartGlide();
        }

        public static string IdontKnow()                                          // Retuns one of the default mesasges
        {
            return DefaultMesg[RandomClass.Next(0, DefaultMesg.Count)].ToString();
        }

        public static void SendSay()                                            // Sending the say itself
        {
            string who = LastFrom;
            string message = SendMessage;

            if (who == GContext.Main.Me.Name && AvoidSelfLoop) return;

            if (message.Length <= 1 && SendDefault)
            {
                AIMLBOTLog("I don't know what to send back", true);
                message = IdontKnow();
                AddBlackList(who);

            } else if (message.Length <= 1) return;

            OutOfCombatWait(2000);

            if (GContext.Main.Me.IsDead) return;

            if (StopGliding)
            {
                GContext.Main.KillAction("AIMLbot4Glider", false);
            }

            if (RandomMove && StopGliding) RandomJumpOrMove();
            if (UseFace && StopGliding) FacePlayer(who);

            DoGrayList(who);

            if (UseMisspell) message = MisSpelling(message);

            AIMLBotChatLog("[" + GContext.Main.Me.Name + "] say: " + message);
            if (MSNsend) MSNmessage = "[" + GContext.Main.Me.Name + "] say: " + message;
            Thread.Sleep(RandomClass.Next(CharDelay, CharDelay + (CharDelay / 5)) * message.Length);
            //Interface.SendLineSayCommand + message);
            CopyPasteLine(SayCommand + message);

            if ((MisspellCorrection != "") && UseMisspellCorrection)
            {
                string correct = Correction[RandomClass.Next(0, Correction.Count)].ToString();
                correct = correct.Replace("##", MisspellCorrection);
                Thread.Sleep(RandomClass.Next(CharDelay, CharDelay + (CharDelay / 5)) * correct.Length);
                CopyPasteLine(SayCommand + correct);
                AIMLBotChatLog("[" + GContext.Main.Me.Name + "] say: " + correct + " (Correction)");
                if (MSNsend) MSNmessage = "[" + GContext.Main.Me.Name + "] say: " + correct + " (Correction)";
                MisspellCorrection = "";
            }

            if (StopGliding) GContext.Main.StartGlide();
        }

        public static void SendWisper()                                         // Sending the wisper itself
        {
            string who = LastFrom;
            string message = SendMessage;

            if (message.Length <= 1 && SendDefault)
            {
                AIMLBOTLog("I don't know what to send back, using default message", true);
                message = IdontKnow();
                AddBlackList(who);
            }
            else if (message.Length <= 1)
            {
                AIMLBOTLog("Message is too short to send, enable a default message or expect occasional response can be skipped", true);
                return;
            }

            OutOfCombatWait(2000);

            if (StopGliding)
            {
                GContext.Main.KillAction("AIMLbot", false);
            }
            else
            {
                Thread.Sleep(3 * 1000);
            }

            if (UseFace && StopGliding) FacePlayer(who);

            if (RandomMove && StopGliding) RandomJumpOrMove();

            DoGrayList(who);

            if (UseMisspell) message = MisSpelling(message);

            AIMLBotChatLog("To [" + who + "] : " + message);
            if (MSNsend) MSNmessage = "To [" + who + "] : " + message;
            Thread.Sleep(RandomClass.Next(CharDelay, CharDelay + (CharDelay / 5)) * message.Length);
            //Interface.SendLine(WhisperCommand + who + " " + message); // Instable
            CopyPasteLine(WhisperCommand + who + " " + message);
            //GContext.Main.Interface.SendString(WhisperCommand + who + " " + message + "\n"); // Why not ???

            if ((MisspellCorrection != "") && UseMisspellCorrection)
            {
                string correct = Correction[RandomClass.Next(0, Correction.Count)].ToString();
                correct = correct.Replace("##", MisspellCorrection);
                Thread.Sleep(RandomClass.Next(CharDelay, CharDelay + (CharDelay / 5)) * correct.Length);
                CopyPasteLine(WhisperCommand + who + " " + correct);
                AIMLBotChatLog("To [" + who + "] : " + correct + " (Correction)");
                if (MSNsend) MSNmessage = "To [" + who + "] : " + correct + " (Correction)";
                MisspellCorrection = "";
            }
            if (StopGliding) GContext.Main.StartGlide();
        }

        public static void RandomJumpOrMove()                                   // Do something randomly to look alive.
        {

            if (RandomClass.Next(1, 101) <= JumpLikelihood)
            {
                AIMLBOTLog("Jumping to look alive", true);
                GContext.Main.SendKey("Common.Jump");
            }
            else
            {
                AIMLBOTLog("Moving a bit to look alive", true);
                int MoveWhere = RandomClass.Next(1, 5);
                switch (MoveWhere)
                {
                    case 1:
                        GContext.Main.PressKey("Common.Forward");
                        Thread.Sleep(RandomClass.Next(120, 450));
                        GContext.Main.ReleaseKey("Common.Forward");
                        break;
                    case 2:
                        GContext.Main.PressKey("Common.StrafeLeft");
                        Thread.Sleep(RandomClass.Next(120, 450));
                        GContext.Main.ReleaseKey("Common.StrafeLeft");
                        break;
                    case 3:
                        GContext.Main.PressKey("Common.StrafeRight");
                        Thread.Sleep(RandomClass.Next(120, 450));
                        GContext.Main.ReleaseKey("Common.StrafeRight");
                        break;
                }
            }
        }

        public static void AddBlackList(string who)                             // Add someone to the BlackList
        {
            if (!UseBlacklist) return;                          // Don't do anything if blacklisting is disabled
            BlackList.Add(who);
            AIMLBOTLog("Blacklisting : " + who, false);
        }

        public static void AddWhiteList(string who)                             // Add someone to the WhiteList
        {
            WhiteList.Add(who);
            AIMLBOTLog("Whitelisting : " + who, false);
        }

        public static bool CheckBlackList(string who)                           // Check if user is on the BlackList
        {
            if (!UseBlacklist) return false;

            if (BlackList.IndexOf(who) != -1)
            {
                BlacklistCount++;
                AIMLBOTLog("Number of blacklist incidents: " + BlacklistCount, true);

                if (BlacklistCount >= MaxBlacklistCount)
                {
                    AIMLBOTLog("Max. number of blacklist incidents reached");                    
                    
                    OutOfCombatWait(RandomClass.Next(800, 2000));
                    
                    GContext.Main.HearthAndExit();
                }
                return true;
            }
            return false;
        }

        public static bool CheckWhiteList(string who)                           // Check if user is on the WhiteList
        {

            if (WhiteList.IndexOf(who) != -1)
            {
                return true;
            }
            return false;
        }

        public static void DoGrayList(string who)                               // Add someone and see if he is not there to often
        {
            GraykList.Add(who);

            int NoOfMessages = 1;

            for (int i = 1; i <= GraykList.Count - 1; i++)
            {
                if (GraykList[i].ToString() == who)
                {
                    NoOfMessages++;
                }
            }
            AIMLBOTLog("Number of messages from " + who + " is : " + NoOfMessages, true);
            if (NoOfMessages >= MaxGrayListCount + 1)
            {
                AddBlackList(who);
            }
        }

        public static bool CheckPartyMembersClose(string Who)                   // True if Who is a party member close
        {
            if (GContext.Main.IsGliding && GContext.Main.IsAttached)
            {
                GUnit tmp = StringToGunitClose(Who);

                if (tmp == null) return false;

                long GUID = tmp.GUID;

                long[] templist = GContext.Main.Party.GetPartyMembers();

                for (int x = 0; x < templist.Length; x++)
                {
                    if (GUID == templist[x])
                    {
                        //AIMLBOTLog(Who + " is a party member", true);
                        return true;
                    }
                }
                //if (templist.Length >= 1) AIMLBOTLog("No matching party members found");
            }
            return false;
        }

        public static bool CheckResendMessage(string mesg)                      // Check if this message was resondly send
        {
            if (mesg.Length <= 1) return false;

            if (CleanMessageSendTimer.IsReady)
            {
                MessageSend.Clear();
                AIMLBOTLog("Clear ResendMessage list", false);
            }

            CleanMessageSendTimer.Reset();

            string LowerMesg = RemoveDot(mesg.ToLower());

            int y = 100;
            int z = 100;

            foreach (string Line in MessageSend)
            {
                y = Compare(Line, LowerMesg);
                //AIMLBOTLog("Compaired " + Line + " with "+ LowerMesg +" = " + y + "% differance");
                if (y <= z) z = y;
            }

            //AIMLBOTLog("Compaired : " + z + "% lowest differance");

            if (z <= MaxLevenshteinDistance) return true;

            if (MessageSend.IndexOf(LowerMesg) == -1)
            {
                MessageSend.Add(LowerMesg);
            }

            return false;
        }

        public static int Compare(string s, string t)                           // LevenshteinDistance
        {
            int n = s.Length;
            int m = t.Length;

            int longest = m;
            if (n >= m) longest = n;

            int[,] d = new int[n + 1, m + 1];

            // Step 1
            if (n == 0)
            {
                return m;
            }

            if (m == 0)
            {
                return n;
            }

            // Step 2
            for (int i = 0; i <= n; d[i, 0] = i++)
            {
            }

            for (int j = 0; j <= m; d[0, j] = j++)
            {
            }

            // Step 3
            for (int i = 1; i <= n; i++)
            {
                //Step 4
                for (int j = 1; j <= m; j++)
                {
                    // Step 5
                    int cost = (t[j - 1] == s[i - 1]) ? 0 : 1;

                    // Step 6
                    d[i, j] = Math.Min(
                        Math.Min(d[i - 1, j] + 1, d[i, j - 1] + 1),
                        d[i - 1, j - 1] + cost);
                }
            }
            // Step 7
            return (d[n, m] * 100) / longest;
        }

        public static string MakeAnswer(string User, string input)              // Get AIMLbot answer
        {
            //if (myUser.ToString() != User)

            if (OldUser != User)
            {
                myUser = new User(User, myBot);
            }

            myUser.Predicates.addSetting("name", User);

            // GContext.Main.Log("debug : " + myUser.UserID);       // Test line

            OldUser = User;

            Request r = new Request(input, myUser, myBot);
            Result res = myBot.Chat(r);
            myBot.isAcceptingUserInput = true;

            string output = res.Output;

            if (CheckResendMessage(output) || output.Contains("ERROR:") || DotCount(output) >= 2) //Once
            {
                r = new Request(input, myUser, myBot);
                res = myBot.Chat(r);
                output = res.Output;
            }
            else if (UseRemoveDot) return (RemoveDot(RemoveLineBreaks(output))); else return (RemoveLineBreaks(output));

            if (CheckResendMessage(RemoveLineBreaks(output)) || output.Contains("ERROR:") || DotCount(RemoveLineBreaks(output)) >= 2) //Twice
            {
                r = new Request(input, myUser, myBot);
                res = myBot.Chat(r);
                output = res.Output;
            }
            else if (UseRemoveDot) return (RemoveDot(output)); else return (output);

            if (CheckResendMessage(RemoveLineBreaks(output)) || output.Contains("ERROR:") || DotCount(RemoveLineBreaks(output)) >= 2) //Give up
            {
                output = "";                                                    //Sending back nothing will triger the default message and blacklist
            }

            if (UseRemoveDot) return (RemoveDot(RemoveLineBreaks(output))); else return (RemoveLineBreaks(output));
        }

        public static int DotCount(string In)                                   // Count the number of dot's in a message
        {
            int y = 0;
            foreach (char x in In)
            {
                if (x == '.') y++;
            }
            return y;
        }

        public static bool FacePlayer(string Name)                              // Facing a player if close
        {
            GUnit Target = StringToGunitClose(Name);
            if (Target == null) return false;
            if (Target.DistanceToSelf >= 20) return false;
            if (Target.Name == Name) return Face(Target);
            return false;
        }

        public static void GM_Panic()                                           // Help a GM we need to send someting if enabled and HearthAndExit
        {
            string GM = LastFrom;
            OutOfCombatWait(2000);

            GContext.Main.KillAction("AIMLbot", false);

            if (RandomMove) RandomJumpOrMove();

            Thread.Sleep(RandomClass.Next(CharDelay, CharDelay + (CharDelay / 5)) * GM_Reply.Length);

            //if (GM_Reply_on) Interface.SendLine(WhisperCommand + GM + " " + GM_Reply);
            CopyPasteLine(WhisperCommand + GM + " " + GM_Reply);

            GContext.Main.HearthAndExit();
            AIMLBOTLog("Hoping we are save after the GM chat, Stoped all gliding and exit");
        }

        public static void SpeakWithHim(GUnit CloseGuy)                         // Someone closeby, lets speak to him
        {
            if (CloseGuy == GContext.Main.Me) return;

            OutOfCombatWait(2000);

            if (GContext.Main.Me.IsDead) return;

            if (StopGliding)
            {
                GContext.Main.KillAction("AIMLbot", false);
            }

            if (CloseGuy.IsTargetingMe && !GContext.Main.Me.IsDead)
            {
                AIMLBOTLog(CloseGuy.Name + " is targeting me, move into action right away");
            }
            else
            {
                if (RandomMove && StopGliding) RandomJumpOrMove();

                if (UseFace && StopGliding)
                {
                    Face(CloseGuy);
                }

                Thread.Sleep(RandomClass.Next(800, 2500));

                if (!GContext.Main.Me.IsInCombat && CloseGuy.DistanceToSelf <= VeryCloseDistance && !CloseGuy.IsFacingAway && !CloseGuy.Hover() && !GContext.Main.Me.IsDead)
                {
                    AIMLBOTLog("Moving close, current distance (Before) : " + CloseGuy.DistanceToSelf, true);
                    CloseGuy.ApproachSafe(RandomClass.Next(8, 12), false);
                    AIMLBOTLog("Moving close, current distance (After) : " + CloseGuy.DistanceToSelf, true);
                }
                else
                {
                    AIMLBOTLog("Lets continue the glide " + CloseGuy.Name + " is no longer looking", true);
                    if (StopGliding) GContext.Main.StartGlide();
                    return;
                }
            }

            if (PVPfaction(CloseGuy) == PVPfaction(GContext.Main.Me) || !UseEmote && !GContext.Main.Me.IsDead)
            {
                string RNDTYMsg = Opening[RandomClass.Next(0, Opening.Count)].ToString();

                if (CheckResendMessage(RNDTYMsg))               // Once
                {
                    RNDTYMsg = Opening[RandomClass.Next(0, Opening.Count)].ToString();
                }
                if (CheckResendMessage(RNDTYMsg))               // Twice
                {
                    RNDTYMsg = Opening[RandomClass.Next(0, Opening.Count)].ToString();
                }

                RNDTYMsg = RNDTYMsg.Replace("##", CloseGuy.Name);

                CopyPasteLine(SayCommand + RNDTYMsg);
                AIMLBotChatLog("[" + GContext.Main.Me.Name + "] says: " + RNDTYMsg + " (Initiate)");
                AddWhiteList(CloseGuy.Name);
                if (MSNsend) MSNmessage = "[" + GContext.Main.Me.Name + "] says: " + RNDTYMsg + " (Initiate)";
            }
            else
            {
                string RNDTYMsg = Emotes[RandomClass.Next(0, Emotes.Length)];
                CopyPasteLine(RNDTYMsg + " " + CloseGuy.Name);
                AIMLBotChatLog("Emote : " + RNDTYMsg + " to " + CloseGuy.Name + " (Initiate)");
                if (MSNsend) MSNmessage = "Emote : " + RNDTYMsg + " to " + CloseGuy.Name + " (Initiate)";
            }

            if (!GContext.Main.Me.IsInCombat && CloseGuy.DistanceToSelf <= VeryCloseDistance &&
                RandomMove && StopGliding && !GContext.Main.Me.IsDead)
            {
                RandomJumpOrMove();
            }
            else
            {
                AIMLBOTLog("Lets continue the glide " + CloseGuy.Name + " is no longer looking (2)", true);
                if (StopGliding) GContext.Main.StartGlide();
                return;
            }

            if (!GContext.Main.Me.IsInCombat && CloseGuy.DistanceToSelf <= VeryCloseDistance && !GContext.Main.Me.IsDead)
            {
                AIMLBOTLog(CloseGuy.Name + " is still very close lets wait a bit", true);
                Thread.Sleep(RandomClass.Next(1100, 3500));
            }
            else
            {
                AIMLBOTLog("Lets continue the glide " + CloseGuy.Name + " is no longer looking (3)", true);
                if (StopGliding) GContext.Main.StartGlide();
                return;
            }
            AIMLBOTLog("Let us just continue the glide, hoping we pretended enough", true);
            if (StopGliding) GContext.Main.StartGlide();
        }

        public static int PVPfaction(GUnit who)                                 // Returns the PVP faction 1 = Alliance, 2 = Horde, -1 = Unknown
        {
            int FactionID = who.FactionID;

            switch (FactionID)
            {
                case 1: return 1;
                case 3: return 1;
                case 4: return 1;
                case 115: return 1;
                case 1629: return 1;
                case 2: return 2;
                case 5: return 2;
                case 6: return 2;
                case 116: return 2;
                case 1610: return 2;
            }
            return -1;
        }

        public static GUnit StringToGunitClose(string name)                     // Return GUnit of Player close?
        {
            GUnit[] plys = GObjectList.GetUnits();

            foreach (GUnit p in plys)
            {
                if (p.Name == name)
                {
                    return p;
                }
            }
            return null;
        }

        public static bool Face(GUnit player)                                   // Facing a GUnit
        {

            if (Math.Abs(player.Bearing) < Math.PI / 8) return true;
            int x = 0;
            do
            {

                double b = player.Bearing;
                x++;
                if (b < -Math.PI / 8)   // to the left
                {
                    GContext.Main.PressKey("Common.RotateLeft");
                }
                else if (b > Math.PI / 8)  // to the rigth
                {
                    GContext.Main.PressKey("Common.RotateRight");
                }
                else
                {
                    GContext.Main.ReleaseKey("Common.RotateLeft");
                    GContext.Main.ReleaseKey("Common.RotateRight");
                    return true;
                }

                Thread.Sleep(RandomClass.Next(50, 200));
            } while (!GContext.Main.Me.IsInCombat && !GContext.Main.Me.IsDead && !(x >= 2500 / 50));

            AIMLBOTLog("Facing failed, Timeout, Dead, InCombat?", true);
            return true;
        }

        public static int NuberOfClosePlayers()                                 // How much players are close?
        {
            GPlayer[] plys = GObjectList.GetPlayers();
            int counter = 0;

            foreach (GPlayer p in plys)
            {
                if (p.DistanceToSelf <= CloseDistance && !CheckPartyMembersClose(p.Name)) counter++;
            }
            return counter - 1;
        }

        public static GUnit PlayerLookingClose()                                // Is there a player very very close?
        {
            GPlayer[] plys = GObjectList.GetPlayers();
            GPlayer ClosestPlayer = null;

            foreach (GPlayer p in plys)
            {
                if (p.IsTargetingMe && p.IsSameFaction) return p;
                if (p.IsPlayer && p != GContext.Main.Me &&
                    p.DistanceToSelf <= VeryCloseDistance &&
                    !p.IsFacingAway && !p.IsDead &&
                    !CheckPartyMembersClose(p.Name) &&
                    p.IsNotDying && !CheckBlackList(p.Name)
                    )
                {
                    if (ClosestPlayer == null || p.DistanceToSelf < ClosestPlayer.DistanceToSelf)
                        ClosestPlayer = p;
                }
            }
            return ClosestPlayer;
        }

        public static string RemoveDot(string InputStr)                         // Remove the full stop if this is at the end
        {
            if (InputStr.Length <= 1) return InputStr;
            if (!UseRemoveDot) return InputStr;

            if (Right(InputStr, 1) == ".")
            {
                return (InputStr.Substring(0, InputStr.Length - 1));
            }
            else return (InputStr);
        }

        public static string MisSpelling(string InputStr)                       // Changes a character to one close on international (qwerty) keyboard
        {
            if (RandomClass.Next(1, 101) >= misspellLikelihood)
            {
                MisspellCorrection = "";
                return InputStr;
            }

            string OutputStr = InputStr;

            int letterNumber = RandomClass.Next(0, Alphabet.Length);
            char y = Alphabet[letterNumber];

            while (InputStr.IndexOf(y) == -1)
            {
                letterNumber = RandomClass.Next(0, Alphabet.Length);
                y = Alphabet[letterNumber];
            }

            char z;
            if (RandomClass.Next(1, 3) >= 1) z = TypoList1[letterNumber]; else z = TypoList2[letterNumber];

            foreach (char x in InputStr)
            {
                if (x == y)
                {
                    OutputStr = InputStr.Replace(x, z);
                    MisspellCorrection = ChangedWord(InputStr, OutputStr);
                }
            }

            return (OutputStr);
        }

        public static int WordCount(string In)                                  // Counts the number of words in a string
        {
            string[] words = In.Split(new char[] { ' ' });

            return words.Length;
        }

        public static string ChangedWord(string Origional, string Changed)      // Return the first changed word for correction
        {
            string[] WordsOrigional = Origional.Split(new char[] { ' ' });
            string[] WordsChanged = Changed.Split(new char[] { ' ' });

            for (int x = 0; x <= WordsOrigional.Length; ++x)
            {
                if (WordsOrigional[x] != WordsChanged[x])
                {
                    return WordsOrigional[x];
                }
            }
            return "";
        }

        public static string Right(string strParam, int iLen)	                // Some default Sting manupilation
        {
            if (iLen > 0)
                return strParam.Substring(strParam.Length - iLen, iLen);
            else
                return strParam;
        }

        public static string RemoveLineBreaks(string In)                        // Removes all line breaks when they are in the AIML response
        {
            string Out;

            Out = In.Replace((char)13, ' ');
            Out = Out.Replace("\r", " ");
            Out = Out.Replace("\n", " ");

            Out = Out.Replace("  ", " ");
            Out = Out.Replace("  ", " ");
            Out = Out.Replace("  ", " ");
            Out = Out.Replace("  ", " ");

            return Out;
        }

        public static void CopyPasteLine(string InputStr)                       // Alternative for Gliders SendLine (See ClipBoardHelper.cs)
        {
            if (GContext.Main.IsAttached)
            {
                ClipboardHelper.Serialize("Clipboard.tmp");
                GContext.Main.SendKey("Common.Return");
                Thread.Sleep(100);
                ClipboardHelper.SetClipboardText(InputStr + "  ");
                GContext.Main.SendKey("Common.Paste");
                Thread.Sleep(100);
                GContext.Main.SendKey("Common.Backspace");
                GContext.Main.SendKey("Common.Backspace");
                GContext.Main.SendKey("Common.Return");
                ClipboardHelper.Deserialize("Clipboard.tmp");
            }
            else
            {
                AIMLBOTLog("Can not copy/past line, Glider is not attached !", false);
            }
        }

        //------------------------------------------Save Lists----------------------------------------------

        public static void Save2DList(ArrayList List, string FileName)          // Save a list(array) to a file
        {
            int count = 0;
            StreamWriter textOut =
                new StreamWriter(
                new FileStream(FileName, FileMode.Create, FileAccess.Write));

            foreach (string Line in List)
            {
                textOut.WriteLine(Line);
                count++;
            }
            textOut.Close();
            AIMLBOTLog("Saved " + count + " players in the blacklist");
        }

        public static ArrayList Get2DList(string FileName)                      // Load list from file
        {
            int count = 0;
            StreamReader textIn =
                new StreamReader(
                new FileStream(FileName, FileMode.OpenOrCreate, FileAccess.Read));

            ArrayList List = new ArrayList();

            while (textIn.Peek() != -1)
            {
                string Line = textIn.ReadLine();
                
                if (Line.Length >= 1)
                {
                    List.Add(Line);
                    count++;
                }
            }

            textIn.Close();
            AIMLBOTLog("Loaded " + count + " players from the blacklist");
            return List;

        }

        //--------------------------------------AIMLBot log helper------------------------------------------

        public static void AIMLBotChatLog(string mesg)                          // Log to  ChatLog (Debug)
        {
            DateTime Now = System.DateTime.Now;

            string minutes = Now.Minute.ToString();

            if (minutes.Length == 1) minutes = "0" + Now.Minute.ToString();

            string logLine = System.String.Format("{0:G} - {1}", Now.Hour + ":" + minutes, mesg);
            MonitorLog.AddToLog(logLine);

            AIMLBOTLog(mesg, true);

        }
        
        public static void AIMLBOTLog(string mesg)                              // Log to glider (Full)
        {
            AIMLBOTLog(mesg, false);
        }

        public static void AIMLBOTLog(string mesg, bool debug)                  // Log to glider
        {
            AIMLFileLog(mesg);

            if (debug == false)
            {
                GContext.Main.Log("[AIMLbot] " + mesg);
            }
            else
            {
                GContext.Main.Debug("[AIMLbot] " + mesg);
            }
        }

        public static void CleanLog()                                           // When logfil is to big rename it
        {
            try
            {
                System.IO.FileInfo fileInfo = new System.IO.FileInfo("Classes\\AIMLbot4Glider\\AIMLbot.log");
                if (fileInfo.Length >= 1024*1024)   // When bigger then 1MB
                {
                    File.Copy("Classes\\AIMLbot4Glider\\AIMLbot.log", "Classes\\AIMLbot4Glider\\AIMLbot_" + System.DateTime.Now.ToShortDateString().Replace('/','_') + ".log"); // Copy old one to backup
                    File.Delete("Classes\\AIMLbot4Glider\\AIMLbot.log");        // Delete old one
                    AIMLBOTLog("Log Files is to big, renaming it to :" + "AIMLbot_" + System.DateTime.Now.ToShortDateString().Replace('/','_') + ".log"); // This auto creates a new one
                }
            }
            catch (Exception e)
            {
                GContext.Main.Log("[AIMLbot] Error: Could not access the Logfile.");
                GContext.Main.Log("[AIMLbot] " + e.Message);
            } 
        }

        public static void AIMLFileLog(string mesg)                             // Log only in AIMLbot.log
        {
            
            try
            {
                System.IO.StreamWriter LogFile = System.IO.File.AppendText("Classes\\AIMLbot4Glider\\AIMLbot.log");
                string logLine = System.String.Format("{0:G}: {1}", System.DateTime.Now, mesg);
                LogFile.WriteLine(logLine);
                LogFile.Close();
            }
            catch (Exception e)
            {
                GContext.Main.Log("[AIMLbot] Error: Could write to Logfile");
                GContext.Main.Log("[AIMLbot] " + e.Message);
            } 
        }

    }
}